/* 
 * File:   Sesion.cpp
 * Author: Maximiliano Monzon (82341)
 * 
 * Created on October 18, 2012, 7:00 PM
 */

#include <stdio.h>
#include <iostream>
#include <stdlib.h>
#include <string.h>
#include <unistd.h>
#include <sys/types.h> 
#include <sys/socket.h>
#include <netinet/in.h>
#include <arpa/inet.h>
#include "server_Sesion.h"
#include "common_Thread.h"
#include "common_ProtocoloConstantes.h"
#include "common_MutexScopeLocker.h"
#include "server_SockEndPointAsincronico.h"
#include "common_Descriptor.h"


using namespace std;
using namespace TP;
using namespace TP::Comunicacion;
using namespace TP::Threading;
using namespace TP::Comunicacion::Asincronica;

#define CONEXION_FINALIZADA 0
#define CONEXION_ERROR -1
#define BUFFER_SIZE 256

Sesion::Sesion(SockEndPointAsincronico* pEndPoint) {
    
    this->manejadorSesionEvento = NULL;
    _sesionFinalizada = true;
    _autenticada = false;
    _endPoint = pEndPoint;
    _credencial = "";
}

Sesion::~Sesion() {
    // delete _endPoint;
}

void Sesion::agregarMensajeEntranteManejador(IMensajeEntranteManejador* pManejador){
    this->mensajeSesionManejadores.push_back(pManejador);
}

void Sesion::agregarManejadorSesionEvento (IManejadorSesionEvento* pManejador){
    this->manejadorSesionEvento = pManejador;
}

void Sesion::Iniciar() throw (Excepcion&){
    
    try
    {
        SetFinalizada(false);
        _endPoint->Iniciar();
        
        // Inicio la tarea de la sesion.
        Thread::Iniciar();
    }
    catch (Excepcion& pEx)
    {
        throw;
    }

}

void Sesion::Finalizar() throw (Excepcion&){
    
    try
    {
        SetFinalizada(true);
        _endPoint->Finalizar();
        
        // Finalizo las operaciones.
        Thread::Finalizar();
    }
    catch (Excepcion& pEx)
    {
        throw;
    }
}

void Sesion::Responder (const string& pMensaje) throw (Excepcion&) {
    
    try
    {
        _endPoint->Escribir(reinterpret_cast<const uint8_t*> (pMensaje.c_str()), pMensaje.length());
    }        
    catch (Excepcion &ex)
    {
        throw;
    }    
}

void Sesion::tarea(){
    
    /* La sesion tiene como tarea recibir los mensajes entrantes, desencodearlos
     * y notificar el mensaje a sus suscriptores.
     * 
     * La tarea es valida siempre y cuando la conexion no haya sido finaliada
     * por el host.
     */
    while (! GetFinalizada())
    {
        uint8_t* buffer = NULL;
        uint32_t longitud = 0;
        
        try
        {
            _endPoint->Leer(buffer, longitud);

            string mensaje = "";
            for (size_t i = 0; i < longitud; i++)
            {
                mensaje += (char)buffer [i];
            }
            
            if (longitud > 0)
            {
                if (EsCredencial (mensaje))     
                    _credencial = mensaje;
                else
                {
                    this->notificarMensaje(mensaje);
                }
            }
            
            delete [] buffer;
        }
        catch (Excepcion &ex)
        {
            if (NULL != buffer)
            {
                delete [] buffer;
            }
            
            if (!GetFinalizada())
            {
                if (NULL != this->manejadorSesionEvento)
                {
                        this->manejadorSesionEvento->eventoConexionFinalizada((IEnviante*) this, ex.what());
                }
                
                //SetFinalizada(true);
            }
        }
    }
}

const string& Sesion::notificarMensaje (const string& pMensaje){

    // Notifico el mensaje a los servicios.
    for (vector<IMensajeEntranteManejador*>::iterator it = this->mensajeSesionManejadores.begin(); it != this->mensajeSesionManejadores.end(); ++it)
    {
        (*it)->mensajeEntranteManejador((IMensajero*) this, pMensaje);                
    }
    
    return pMensaje;
}

bool Sesion::GetFinalizada (){
    MutexScopeLocker _locker (_sesionFinalizadaMutex);
    return _sesionFinalizada;
}

bool Sesion::SetFinalizada (bool pValor){
    MutexScopeLocker _locker (_sesionFinalizadaMutex);
    _sesionFinalizada = pValor;
    return _sesionFinalizada;
}

bool Sesion::GetAutenticada(){
    MutexScopeLocker _locker (_autenticadaMutex);
    return _autenticada;
 }

bool Sesion::SetAutenticada(bool pValor){
    MutexScopeLocker _locker (_autenticadaMutex);
    _autenticada = pValor;
    return _autenticada;
}

string Sesion::GetUsuario(){
    MutexScopeLocker _locker (_usuarioMutex);
    return _usuario;
}

string Sesion::SetUsuario(const string& pValor){
    
    MutexScopeLocker _locker (_usuarioMutex);
    _usuario = pValor;
    
    return _usuario;
}

bool Sesion::EsCredencial (const string & pMensaje){
    
    try
    {
        Descriptor descriptor (SEPARADOR_CAMPO);
        descriptor.parse (pMensaje);

        return (USUARIO_CREDENCIAL == descriptor.data(0));
    }
    catch (IndiceFueraRangoExcepcion &ex)
    {
        return false;
    }
}

string& Sesion::GetCredencial (){
    return _credencial;
}

void Sesion::Segurizar(const string &pClave){
    _endPoint->SetClaveSeguridadCanal(pClave);
}